/*================================================================
*   Copyright (C) 2020 belonging to YangZhengQing. All rights reserved.
*   
*   文件名称：semaphore.c
*   创 建 者：YangZhengQing
*   创建日期：2020年03月11日
*   描    述：
*
*================================================================*/


//#include "semaphore.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define FTOK_PATH "../apue"//路径必须存在
#define PROJ_ID 10//8bit

//定义一个信号量集联合
union semun
{
	int val;
	struct semid_us *buf;
	unsigned short *arry;
};

/*
 功能：信号量初始化
 参数：无
 返回：
	成功返回信号量值
	失败返回-1
 */
int semaphore_init(void)
{
	key_t					key = -1;
	int						sem_val = -1;
	union semun				sem_union;
	int						rv = -1;

	key = ftok(FTOK_PATH,PROJ_ID);//获取IPC关键字
	if(key < 0)
	{
		printf("ftok error:%s\n",strerror(errno));
		return -1;
	}

	sem_val = semget(key, 1, IPC_CREAT|0644);//获取信号量，当信号量不存在时，创建一个心的
	if(sem_val < 0)
	{
		printf("semget error:%s\n",strerror(errno));
		return -1;
	}

	rv = semctl(sem_val, 0, SETVAL, sem_union);//初始化信号量集，设置信号量集中一个单独信号量的值。
	if(rv < 0)
	{
		printf("semctl error:%s\n",strerror(errno));
		return -1;
	}


	return sem_val;
}


/*
 功能：从系统中删除信号量集合
 参数：
	sem_val:信号量值
 返回：
	成功返回0;
	失败返回-1;
 */

int semaphore_delete(int sem_val)
{
	union semun				sem_union;

	if(semctl(sem_val, 0, IPC_RMID, sem_union) < 0)
	{
		printf("semctl delete error:%s\n",strerror(errno));
		return -1;
	}

	return 0;
}

/*
 功能：P操作
 参数：
	sem_val:信号量值
 返回：
	成功返回0
	失败返回-1
 */

int semaphore_p(int sem_val)
{
	struct sembuf		_sembuf;//信号量操作结构体

	//初始化结构体
	_sembuf.sem_num		= 0;//信号集中第一个信号的编号
	_sembuf.sem_op		= -1;//P操作
	_sembuf.sem_flg		= SEM_UNDO;//程序结束时，信号值恢复

	if(semop(sem_val, &_sembuf, 1) < 0)
	{
		printf("semop p error:%s\n",strerror(errno));
		return -1;
	}

	return 0;
}


/*
 功能：V操作
 参数：
	sem_val:信号量值
 返回：
	成功返回0
	失败返回-1
 */

int semaphore_v(int sem_val)
{
	struct sembuf		_sembuf;//信号量操作结构体

	//初始化结构体
	_sembuf.sem_num		= 0;//信号集中第一个信号的编号
	_sembuf.sem_op		= 1;//V操作
	_sembuf.sem_flg		= SEM_UNDO;//程序结束时，信号值恢复

	if(semop(sem_val, &_sembuf, 1) < 0)
	{
		printf("semop p error:%s\n",strerror(errno));
		return -1;
	}

	return 0;
}



int main(int argc, char **argv)
{
	int						pid = -1;
	int						sem_val = -1;
	
	sem_val = semaphore_init();
	if(sem_val < 0)
	{
		exit(0);
	}

	pid = fork();
	if(pid < 0)
	{
		printf("fork error:%s\n",strerror(errno));
		exit(0);
	}
	else if(pid == 0)
	{
		printf("child is working...\n");
		sleep(5);
		printf("child working over!\n");
		semaphore_v(sem_val);
		exit(0);//子进程退出
	}

	printf("father is blocking...\n");

	semaphore_p(sem_val);//若父进程线运行，p操作使信号量小于0,父进程阻塞直到子进程V操作
	
	

	printf("father woking over...\n");

	semaphore_delete(sem_val);//销毁信号集

	printf("program exit!\n");

	return 0;

}
